/* ********************************************************************************************
*  Alvin Baldemeca
*  Tetris Project
*  Course: TCSS 305 , Alan Fowler
*  Term: Spring 2012
*  UNIVERISTY OF WASHINGTON TACOMA
*
*
**********************************************************************************************/


package controller;



import java.awt.Color;
import model.IPiece;
import model.JPiece;
import model.LPiece;
import model.OPiece;
import model.SPiece;
import model.TPiece;
import model.ZPiece;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;





/**
 * This class test the Board Class.
 * @author Alvin Baldemeca
 * @version 5/3/2012
 *
 */
public class BoardTest
{
  
  /**
   * Use for testing the step() method of the Board Class.
   */
  private static final int WIDTH = 9;
  /**
   * The Board to test.
   */
  private Board my_testboard;
  
  /**
   * The Board to test.
   */
  private Board my_testboard1;
  
  /**
   * The a second board to test.
   */
  private Board my_testboard2;
  
  /**
   * Used to test the piece produce by the board.
   */
  private TPiece my_piece;
  
  /**
   * Rotation vector for the TPiece.  Compare the rotation
   * of the first sequential Piece which is a TPiece.
   */
  private final int [][][] my_tpiece_rotation = new int[][][] 
  { 
    {{1, 0}, {0, 1}, {1, 1}, {2, 1}},
    {{1, 0}, {1, 1}, {2, 1}, {1, 2}},
    {{0, 1}, {1, 1}, {2, 1}, {1, 2}},
    {{1, 0}, {0, 1}, {1, 1}, {1, 2}} 
  };

  
  /**
   * Sets up and initializes the fields.
   */
  @Before
  public void setUp() 
  {
    my_testboard = new Board(20, 10);
    my_testboard.setRandom(false);
    my_testboard.createPiece();                                         //        []  
    my_testboard.createPiece(); // I'm testing the second Piece in the sequence [][]
    my_piece = (TPiece) my_testboard.getCurrentPiece();                       //         []   
    my_testboard1 = new Board(20, 10);
    my_testboard1.setRandom(false);
    my_testboard2 = new Board(30, 10);
    my_testboard.getCurrentPiece();
    my_testboard1.createPiece();
  }
  

  /**
   * Method to test the Constructor.
   */
  @Test
  public void testConstructor()
  { 
    assertEquals("Should equal the height set", my_testboard.getContainer().length, 20);
    assertEquals("Should equal the height set", my_testboard.getContainer()[0].length, 10);
    assertEquals("Sequence should start with a TPiece", my_piece.getClass(), TPiece.class);
    
  }
  
  /**
   * Test the moveLeft() method.
   */
  @Test
  public void testMoveLeft()
  {
    my_testboard.moveLeft();
    assertEquals("The piece should not move", my_testboard.getCurrentPiece().getX(), 2);
    my_testboard.moveDown();
    my_testboard.moveDown();
    my_testboard.moveDown();
    assertEquals("Piece does not start where it should", 
                 my_testboard.getCurrentPiece().getX(), 2);
    
    my_testboard.moveLeft();
    assertEquals("Piece does not move correctly", my_testboard.getCurrentPiece().getX(), 1);
    my_testboard.moveLeft();
    assertEquals("Should be at the boarder", my_testboard.getCurrentPiece().getX(), 0);
    my_testboard.moveLeft();
    assertEquals("Piece moved pass the border", my_testboard.getCurrentPiece().getX(), 0); 
    
  }
  
  /**
   * Test the moveLeft() method.
   */
  @Test
  public void testMoveRight()
  { 
    my_testboard.moveRight();
    assertEquals("Piece did not move to the right.",
                 my_testboard.getCurrentPiece().getX(), 3);
    
    my_testboard.moveDown();  // -1
    my_testboard.moveDown();  //  0
    my_testboard.moveRight(); // 3
    assertEquals("Piece did not move to the right", my_piece.getX(), 4);
    
    my_testboard.moveRight(); //4
    my_testboard.moveRight(); //5
    my_testboard.moveRight(); //6
    my_testboard.moveRight(); //7
    my_testboard.moveRight(); //8
    assertEquals("Piece is not at the right border", my_piece.getX(), 8);
    my_testboard.moveRight(); //8
    assertEquals("Piece moved pass the border", my_piece.getX(), 8);
    
    
//    my_testboard.moveRight();
//    System.out.println(my_testboard.getPiece().getX() +
//               "  " + my_testboard.getPiece().getY());
//    System.out.println(my_testboard + " \n \n");
    
  }
  
  /**
   * Test the moveDown() method.
   */
  @Test
  public void testMoveDown()
  {
    assertEquals("The starting point is not correct", 
                 my_testboard.getCurrentPiece().getY(), -1);
    my_testboard.moveDown();
    assertEquals("The piece is not moving down", my_testboard.getCurrentPiece().getY(), 0);
    for (int i = 0; i < 19; i++)
    {
      my_testboard.moveDown(); 
    }
    assertEquals("Piece should be at the bottom", my_testboard.getCurrentPiece().getY(), 19);
    my_testboard.moveDown();
    assertEquals("Piece moved pass the bottom", my_testboard.getCurrentPiece().getY(), 19);  
  }
  
  /**
   * Test the rotation method of the Board Class.
   */
  @Test
  public void testRotate()
  {                                                                   // |      
    my_testboard.rotate();                                            // |    [][][]
    assertArrayEquals("Piece did not rotate properly." ,              // |      []
                      my_tpiece_rotation[0], my_piece.getRotation()); //-----------
    
    my_testboard.moveDown(); 
    my_testboard.moveDown();                                      
                                                                    //_____________
                                                                    //|    [][][]
                                                                    //|      []  
    my_testboard.rotate();
    assertArrayEquals("Piece did not rotate properly " ,             //________[]_____
                      my_tpiece_rotation[1], my_piece.getRotation()); //|      [][]
                                                                      //|      []
   
                                                                        
    my_testboard.moveDown();                                          // ____________  
    my_testboard.rotate();                                            // |      
    assertArrayEquals("Piece did not rotate properly  " ,             // |      []
                      my_tpiece_rotation[2], my_piece.getRotation()); // |    [][][]

    
  }
 
  /**
   * Test the step() method of the Board Class.
   */
  @Test
  public void testStep()
  {
    my_testboard.step();
    assertEquals("The piece is not moving down", my_testboard.getCurrentPiece().getY(), 0);
    
    for (int i = 0; i < 19; i++) //215
    {
      my_testboard.step();   
    }  
    assertEquals("The piece is not moving down", my_testboard.getCurrentPiece().getY(), 19);
    assertEquals("Should be the TPiece",
                 my_testboard.getCurrentPiece().getClass(), TPiece.class);
    my_testboard.step(); 
    
    //Next piece after the piece 
    //is frozen on the board.
    assertEquals("The next piece is not an LPiece", 
                 my_testboard.getCurrentPiece().getClass(), IPiece.class);  
    
    my_testboard.step();  
    
    //The privous piece
    assertEquals("Should be the JPiece", my_piece.getClass(), TPiece.class); 
    
    
    
    testStep2();
  }
  
  /**
   * This continues to test the step method till lines are cleared.
   */
  private void testStep2()
  {
    
    for (int i = 0; i < 181; i++) //200               // |[][][][][][][][][][]| Row 16
    {                                                 // |[]    [][][][][][][]| Row 17
      my_testboard1.step();                           // |[][][][][][][][][][]| Row 18
    }                                                 // |[]    [][][][][][][]| Row 19
  
    
    final Color[][] copy1 = my_testboard1.getContainer();
    for (int i = 0; i < WIDTH; i++)
    {
      if (copy1[18][i] == null && copy1[16][i] == null) // These rows should be filled
      {
        fail("All these blocks should be filled  ");
      }
    }  
    
    afterLinesCleared();
    
  }
  
  /**
   * This continues the test initialy rows 18 and 16 are filled then we call on the step
   * method which clears the filled rows.
   */
  private void afterLinesCleared()
  {
    
    my_testboard1.step();                                 //Next step clears the rows
    final Color[][] copy2 = my_testboard1.getContainer(); //Need to copy what's on the 
    for (int i = 3; i < WIDTH; i++)                       // board and see if it gets      
    {                                                     // updated
      if (copy2[18][i] == null || copy2[19][i] == null) 
      {                                                 // Cleared row 18 and row 16 
        System.out.println(copy2[18][i] + " i = " + i); // |[]    [][][][][][][]|
        fail("All these blocks should be filled");      // |[]    [][][][][][][]|
      } 
     
      
    }
    restOfspace(copy2);
  }
  
  /**
   * The rest of the test for clearing the space.
   * @param the_copy2 the copy of the board.
   */
  private void restOfspace(final Color[][] the_copy2)
  {
      
    if (the_copy2[19][0] == null || the_copy2[19][1] != null  || the_copy2[19][2] != null)
    {
      System.out.println(the_copy2[18][2] + " i = ");
      fail("All these blocks should be filled");
    }
    
    if (the_copy2[18][0] == null || the_copy2[18][0].equals(the_copy2[18][1]) ||
        the_copy2[18][2] != null)
    {
      fail("All these blocks should be filled");
    }
  }
   
  /**
   * Test the Board in Random mode.
   */
  @Test
  public void testRandom()
  {
    
    assertEquals("Random piece did not start in the middle of the board",
                 my_testboard2.getCurrentPiece().getX(), 4);
    my_testboard2.createPiece();
    
    boolean isvalid = false;
    if (my_testboard.getCurrentPiece().getClass() == IPiece.class ||
        my_testboard.getCurrentPiece().getClass() == JPiece.class ||
        my_testboard.getCurrentPiece().getClass() == SPiece.class ||
        my_testboard.getCurrentPiece().getClass() == ZPiece.class ||
        my_testboard.getCurrentPiece().getClass() == OPiece.class ||
        my_testboard.getCurrentPiece().getClass() == LPiece.class ||
        my_testboard.getCurrentPiece().getClass() == TPiece.class)
    {
      isvalid = true;
    }
    
    assertEquals("Random creat did not creat a valid tetris piece", isvalid, true);
    //test random generator for coverage and make sure the all the pieces were created.
    for (int i = 0; i < 50; i++) //215
    {
      //Un-comment the line below for console output
      //System.out.println(my_testboard2 + " \n \n");
      my_testboard2.step();
    }
    
  }
  
  /**
   * Test the toString, with an empty board.
   */
  @Test
  public void testToString()
  {
    
    final StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 20; i++)
    {
      sb.append("|");
      for (int j = 0; j < 10; j++)
      {
        sb.append("  ");
      }
     
      sb.append("|\n");
    }
    for (int i = 0; i <= 10; i++)
    {
      sb.append("||");
    }
    
    assertEquals(" ", sb.toString(), my_testboard.toString());
    
    
  
  }

}
